#pragma once

#include <vector>
#include <queue>
#include <unistd.h>
#include <pthread.h>
#include "Task.hpp"

using std::vector;
using std::queue;

//初始版本V1：使用线程原生库，实现基本的多线程并发执行任务

static const int N = 5; //线程数[默认]

template<class T>
class ThreadPool
{
public:
    ThreadPool(int num = N)
        :_threads(num)
        ,_num(num)
    {
        //锁 及 条件变量 的初始化
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~ThreadPool()
    {
        //销毁
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }

    //初始化
    void init()
    {
        //TODO
    }

    static void *threadRoutine(void *arg)
    {
        //线程首先剥离
        pthread_detach(pthread_self());

        //获取 this 指针
        ThreadPool<T> *tp = static_cast<ThreadPool<T>*> (arg);

        while(true)
        {
            //1、检测有没有任务，执行 或 等待
            tp->lockQueue();
            while(tp->isEmpty())
            {
                //没有任务，等待
                tp->threadWait();
            }
            T t = tp->popTask();
            tp->unlockQueue();

            t();    //执行任务
            std::cout << "threadRoutine done: " << t.formatResult() << std::endl;
        }
    }

    //启动
    void start()
    {
        for(int i = 0; i < _num; i++)
            pthread_create(&_threads[i], nullptr, threadRoutine, this);
    }

    //装载任务
    void pushTask(const T& t)
    {
        lockQueue();
        _tasks.push(t);
        threadWeakUp();    //装载任务后，唤醒线程，执行任务
        unlockQueue();
    }

    //获取任务 
    T popTask()
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

protected:
    //封装各种功能
    void lockQueue()
    {
        pthread_mutex_lock(&_mtx);
    }

    void unlockQueue()
    {
        pthread_mutex_unlock(&_mtx);
    }

    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }

    void threadWeakUp()
    {
        pthread_cond_signal(&_cond);
    }

    bool isEmpty()
    {
        return _tasks.empty();
    }

private:
    vector<pthread_t> _threads; //存放线程
    int _num;   //线程数

    queue<T> _tasks;    //存放任务（自动扩容）
    pthread_mutex_t _mtx;   //保护任务队列，并发访问时互斥
    pthread_cond_t _cond;   //条件变量，当没有任务时，线程睡眠
};